﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *
 **/

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;

namespace Peter.Common.Controls
{
   /// <summary>
   /// Adorner for the watermark
   /// http://stackoverflow.com/a/836463
   /// </summary>
   internal class WatermarkAdorner : Adorner
   {
      #region Private Fields

      /// <summary>
      /// <see cref="ContentPresenter"/> that holds the watermark
      /// </summary>
      private readonly ContentPresenter m_ContentPresenter;

      #endregion

      #region Constructor

      /// <summary>
      /// Initializes a new instance of the <see cref="WatermarkAdorner"/> class
      /// </summary>
      /// <param name="adornedElement"><see cref="UIElement"/> to be adorned</param>
      /// <param name="watermark">The watermark</param>
      public WatermarkAdorner (UIElement adornedElement, object watermark) :
         base (adornedElement)
      {
         this.IsHitTestVisible = false;

         this.m_ContentPresenter = new ContentPresenter
               {
                  Content = watermark,
                  Opacity = 0.5,
                  Margin = new Thickness (Control.Margin.Left + Control.Padding.Left,
                                          Control.Margin.Top + Control.Padding.Top, 0, 0)
               };

         if (this.Control is ItemsControl && !(this.Control is ComboBox))
         {
            this.m_ContentPresenter.VerticalAlignment = VerticalAlignment.Center;
            this.m_ContentPresenter.HorizontalAlignment = HorizontalAlignment.Center;
         }

         // Hide the control adorner when the adorned element is hidden
         var binding = new Binding ("IsVisible")
                          {
                             Source = adornedElement,
                             Converter = new BooleanToVisibilityConverter ()
                          };
         this.SetBinding (VisibilityProperty, binding);
      }

      #endregion

      #region Protected Properties

      /// <summary>
      /// Gets the number of children for the <see cref="ContainerVisual"/>.
      /// </summary>
      protected override int VisualChildrenCount
      {
         get { return 1; }
      }

      #endregion

      #region Private Properties

      /// <summary>
      /// Gets the control that is being adorned
      /// </summary>
      private Control Control
      {
         get { return (Control)this.AdornedElement; }
      }

      #endregion

      #region Protected Overrides

      /// <summary>
      /// Returns a specified child <see cref="Visual"/> for the parent <see cref="ContainerVisual"/>.
      /// </summary>
      /// <param name="index">A 32-bit signed integer that represents the index value of the child <see cref="Visual"/>. The value of index must be between 0 and <see cref="VisualChildrenCount"/> - 1.</param>
      /// <returns>The child <see cref="Visual"/>.</returns>
      protected override Visual GetVisualChild (int index)
      {
         return this.m_ContentPresenter;
      }

      /// <summary>
      /// Implements any custom measuring behavior for the adorner.
      /// </summary>
      /// <param name="constraint">A size to constrain the adorner to.</param>
      /// <returns>A <see cref="Size"/> object representing the amount of layout space needed by the adorner.</returns>
      protected override Size MeasureOverride (Size constraint)
      {
         // Here's the secret to getting the adorner to cover the whole control
         this.m_ContentPresenter.Measure (Control.RenderSize);
         return Control.RenderSize;
      }

      /// <summary>
      /// When overridden in a derived class, positions child elements and determines a size for a <see cref="FrameworkElement"/> derived class. 
      /// </summary>
      /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
      /// <returns>The actual size used.</returns>
      protected override Size ArrangeOverride (Size finalSize)
      {
         this.m_ContentPresenter.Arrange (new Rect (finalSize));
         return finalSize;
      }

      #endregion
   }
}
